﻿// //  ********************************************************************************
// //  Copyright (C) 2016 Sebastian Kenter. All rights reserved.
// // 
// //  Name    : MultiServerEngine | ServerFramework | TelegramHandlerRegistry.cs
// //  Created : 2016 - 02 - 16 20:53
// //  Modified: 2016 - 02 - 20 12:33
// //  ********************************************************************************

using System;
using System.Collections.Generic;
using System.Linq;
using ExitGames.Logging;
using ServerFramework.Interfaces.Client;
using ServerFramework.Interfaces.Handler;
using ServerFramework.Interfaces.Server;
using TypeDefs;

namespace ServerFramework.Implementation.Handler
{
    public class TelegramHandlerRegistry : ITelegramHandlerRegistry
    {
        public ILogger Logger { get; }

        private readonly Dictionary<TelegramHandlerTypes, List<ITelegramHandler<IClientPeer>>> _clientTelegramHandler;


        private readonly Dictionary<TelegramHandlerTypes, List<ITelegramHandler<IServerPeer>>> _serverTelegramHandler;

        public TelegramHandlerRegistry(ILogger logger)
        {
            Logger = logger;
            _clientTelegramHandler = new Dictionary<TelegramHandlerTypes, List<ITelegramHandler<IClientPeer>>>
                                     {
                                         {
                                             TelegramHandlerTypes.Request,
                                             new List<ITelegramHandler<IClientPeer>>()
                                         },
                                         {
                                             TelegramHandlerTypes.Response,
                                             new List<ITelegramHandler<IClientPeer>>()
                                         },
                                         {
                                             TelegramHandlerTypes.Event,
                                             new List<ITelegramHandler<IClientPeer>>()
                                         }
                                     };
            _serverTelegramHandler =
                new Dictionary<TelegramHandlerTypes, List<ITelegramHandler<IServerPeer>>>
                {
                    {
                        TelegramHandlerTypes.Request,
                        new List<ITelegramHandler<IServerPeer>>()
                    },
                    {
                        TelegramHandlerTypes.Response,
                        new List<ITelegramHandler<IServerPeer>>()
                    },
                    {
                        TelegramHandlerTypes.Event,
                        new List<ITelegramHandler<IServerPeer>>()
                    }
                };
        }

        public bool RegisterServerHandler(ITelegramHandler<IServerPeer> handler)
        {
            // Do we have a handler of that type registered already?
            if (_serverTelegramHandler[handler.HandlerType].Contains(handler)) return false;

            _serverTelegramHandler[handler.HandlerType].Add(handler);

            return true;
        }

        public bool UnregisterServerHandler(ITelegramHandler<IServerPeer> handler)
        {
            // Do we have a handler of that type registered?
            if (!_serverTelegramHandler[handler.HandlerType].Contains(handler)) return false;

            _serverTelegramHandler[handler.HandlerType].Remove(handler);

            return true;
        }

        public bool RegisterClientHandler(ITelegramHandler<IClientPeer> handler)
        {
            // Do we have a handler of that type registered already?
            if (_clientTelegramHandler[handler.HandlerType].Contains(handler)) return false;

            _clientTelegramHandler[handler.HandlerType].Add(handler);

            return true;
        }

        public bool UnregisterClientHandler(ITelegramHandler<IClientPeer> handler)
        {
            // Do we have a handler of that type registered?
            if (!_clientTelegramHandler[handler.HandlerType].Contains(handler)) return false;

            _clientTelegramHandler[handler.HandlerType].Remove(handler);

            return true;
        }

        public ITelegramHandler<IServerPeer> GetServerHandler(TelegramTypes telegramType, byte code, int? subCode)
        {
            Logger.InfoFormat(
                "Trying to find a server handler of type={0} for telegram type={1}, code={2}, sub-code={3}",
                (TelegramHandlerTypes) telegramType, telegramType, (OperationCodes) code,
                (OperationSubCodes) (subCode.HasValue ? Convert.ToInt32(subCode.Value) : Convert.ToInt32(null)));

            // Try to resolve a handler from the dictionary who's handler type matches the telegram type in general and
            // then the codes and sub-codes match
            ITelegramHandler<IServerPeer> handler =
                _serverTelegramHandler[(TelegramHandlerTypes) telegramType].FirstOrDefault(
                    c => c.Code == code && c.SubCode == subCode);

            // Have we found one then return it
            if (handler != null)
            {
                Logger.InfoFormat("Specific handler found: {0}", handler.GetType().Name);
                return handler;
            }

            // Need to "hack" this a little to stay generic cause we don't know the 
            // telegram type to match the code of the handler in the list
            handler =
                _serverTelegramHandler[(TelegramHandlerTypes) telegramType].FirstOrDefault(
                    c =>
                        c.Code == (byte) OperationCodes.DefaultRequest ||
                        c.Code == (byte) OperationCodes.DefaultResponse ||
                        c.Code == (byte) OperationCodes.DefaultEvent && c.SubCode == null);

            if (handler != null)
            {
                Logger.InfoFormat("No specific handler found - returning default handler.");
                return handler;
            }

            Logger.ErrorFormat(
                "Unable to find a server handler of type={0} for telegram type={1}, code={2}, sub-code={3}",
                (TelegramHandlerTypes) telegramType, telegramType, code, subCode);

            return null;
        }

        public ITelegramHandler<IClientPeer> GetClientHandler(TelegramTypes telegramType, byte code, int? subCode)
        {
            Logger.InfoFormat(
                "Trying to find a client handler of type={0} for telegram type={1}, code={2}, sub-code={3}",
                (TelegramHandlerTypes) telegramType, telegramType, (OperationCodes) code,
                (OperationSubCodes) (subCode.HasValue ? Convert.ToInt32(subCode.Value) : Convert.ToInt32(null)));

            // Try to resolve a handler from the dictionary who's handler type matches the telegram type in general and
            // then the codes and sub-codes match
            ITelegramHandler<IClientPeer> handler =
                _clientTelegramHandler[(TelegramHandlerTypes) telegramType].FirstOrDefault(
                    c => c.Code == code && c.SubCode == subCode);

            // Have we found one then return it
            if (handler != null)
            {
                Logger.InfoFormat("Specific handler found: {0}", handler.GetType().Name);
                return handler;
            }

            // Need to "hack" this a little to stay generic cause we don't know the 
            // telegram type to match the code of the handler in the list
            handler =
                _clientTelegramHandler[(TelegramHandlerTypes) telegramType].FirstOrDefault(
                    c =>
                        c.Code == (byte) OperationCodes.DefaultRequest ||
                        c.Code == (byte) OperationCodes.DefaultResponse ||
                        c.Code == (byte) OperationCodes.DefaultEvent && c.SubCode == null);

            if (handler != null)
            {
                Logger.InfoFormat("No specific handler found - returning default handler.");
                return handler;
            }

            Logger.ErrorFormat(
                "Unable to find a client handler of type={0} for telegram type={1}, code={2}, sub-code={3}",
                (TelegramHandlerTypes) telegramType, telegramType, code, subCode);

            return null;
        }
    }
}
